#pragma once
#include <pthread.h>
#include <vector>
#include <semaphore.h>

static const int defaultcap = 5;
template <class T>
class RingQueue
{
public:
    RingQueue(int cap = defaultcap)
    :_que(defaultcap)
    {
        _pstep = 0;
        _cstep = 0;
        _maxcap = cap;

        sem_init(&_sem_sapace, 0, cap);
        sem_init(&_sem_data, 0, 0);

        pthread_mutex_init(&_pmutex, nullptr);
        pthread_mutex_init(&_cmutex, nullptr);

    }

    void push(const T& x)
    {
       //P
       sem_wait(&_sem_sapace);
       //信号量不需要上锁
       pthread_mutex_lock(&_pmutex);
       _que[_pstep] = x;
       //位置后移,维持环形
       _pstep++;
       _pstep %= _maxcap;
       pthread_mutex_unlock(&_pmutex);
       //V操作
       sem_post(&_sem_data);
    }

//消费
    void pop(T* out)
    {
        //P
       sem_wait(&_sem_data);
       pthread_mutex_lock(&_cmutex);
       *out = _que[_cstep];  
       //维持环形
       _cstep++;
       _cstep %= _maxcap;
       pthread_mutex_unlock(&_cmutex);   
       // V操作
       sem_post(&_sem_sapace);
    }

    ~RingQueue()
    {
        sem_destroy(&_sem_sapace);
        sem_destroy(&_sem_data);

        pthread_mutex_destroy(&_pmutex);
        pthread_mutex_destroy(&_cmutex);
    }

private:
    std::vector<T> _que;
    int _maxcap;

    int _pstep;  //生产者下标
    int _cstep;  //消费者下标

    sem_t _sem_sapace;
    sem_t _sem_data;

    pthread_mutex_t _pmutex;
    pthread_mutex_t _cmutex;
};